home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dirut / rm_om.zip / FORMATCH.C < prev    next >
Text File  |  1988-12-24  |  6KB  |  179 lines

  1.     /*
  2.     **    Match the directory pattern given, and call user-supplied routine
  3.     **  once for each match of a pattern with a pointer to the current 
  4.     **  FILE_MATCH packet as argument.  The routine can interrupt the match
  5.     **  process by returning a nonzero value.
  6.     **    Argument type governs the attributes of the file searched for,
  7.     **  the low bits (masked by ALLREALONES) being the normal DOS file
  8.     **  attributes, while the rest are used to control the match algorithm.
  9.     **    Specifically:
  10.     **  READONLY,HIDDEN,SYSTEM,VOLABEL,DIRECTORY,ARCHIVE
  11.     **      these are the normal DOS file attributes.  If VOLABEL is specified,
  12.     **      only the specified disk volume label will be found.  If any of the
  13.     **      bits READONLY, HIDDEN, SYSTEM, and DIRECTORY are specified, the
  14.     **      match will find normal files and any files with these attributes
  15.     **      set.  The ARCHIVE bit cannot be used for searching.
  16.     **  DOTHIDDEN
  17.     **      if set, filenames starting with a dot '.' are considered hidden,
  18.     **      and the HIDDEN bit must be on to retrieve any of these filenames,
  19.     **      except if the name is given as a pattern
  20.     **  MATCHNONWILD
  21.     **      return non-wildcard match items as themselves, even if they do
  22.     **      not exist
  23.     **  RECURSIVE
  24.     **      must have DIRECTORY set also; match recursively, returning the
  25.     **      directory as the last member of itself; initial pattern must be
  26.     **      nonwildcard
  27.     **  DIRFIRST
  28.     **      used with RECURSIVE; return the directory as the first member of
  29.     **      itself as opposed to the default of last member
  30.     **  When any of "x:", "x:/" and "/" are given as patterns, a "*.*" is
  31.     **  appended to them automagically (this makes RECURSIVE matching behave
  32.     **  more logically with all directories).
  33.     **
  34.     **  Returns codes as value:
  35.     **  >0  OK, number of times user routine was called
  36.     **   0  no match
  37.     **  -1  user routine returned nonzero
  38.     **
  39.     ** (c) 1988 by Otto Makela, Jyvaskyla, Finland
  40.     */
  41. #include <model.h>
  42. #include <ctype.h>
  43. #include "formatch.h"
  44.  
  45. #define SETDMA  0x1a
  46. #define SRCHFIR 0x4e
  47. #define SRCHNXT 0x4f
  48.  
  49. #ifdef _LARGEDATA
  50. #define BDOS    bdosx
  51. #define DOS     dosx
  52. #else
  53. #define BDOS    bdos
  54. #define DOS     dos
  55. #endif
  56.  
  57. char *getenv();
  58. char optsepar[2]="/",dirsepar='\\',othersepar='/';
  59.  
  60. int formatch(path,type,routine)
  61. char *path;
  62. int type;
  63. int (*routine)();   {
  64.     int i,code,count=0,wilds=0;
  65.     register char *p,c;
  66.     char *q,*restname;
  67.     char *wildcard="*.*";
  68.     FILE_MATCH file_match;
  69.  
  70. #ifdef  DEBUG
  71.     printf("formatch(\"%s\",0x%x)\n",path,type);
  72. #endif
  73.  
  74.     BDOS(SETDMA, &file_match);
  75.  
  76.         /* Copy initial pattern up to last '/' to match.filename;
  77.            set restname to last wildcard tail */
  78.     for(p=file_match.filename, restname=p, q=path; c=*q; *q++=c)    {
  79.         if(c==':' || c==dirsepar || c==othersepar)  {
  80.             if(c!=':') c=dirsepar;
  81.             restname=p+1;
  82.         } else if(c=='*' || c=='?')
  83.             wilds++;
  84.         if(isupper(c))
  85.             *p++=c=tolower(c);
  86.         else
  87.             *p++=c;
  88.     }
  89.  
  90.         /* Non-wildcard matches: add "*.*" */
  91.     if(!wilds)  {
  92.         p=path;
  93.         if(isalpha(p[0]) && p[1]==':') p+=2;
  94.         if(p[0]=='.')   {
  95.             if(!p[1] || (p[1]=='.' && !p[2]))   {
  96.                 if(p[1])    {
  97.                     p+=2;
  98.                     *p++=dirsepar;
  99.                 }
  100.                 *p='\0';
  101.             }
  102.         } else if(p[0]==dirsepar && !p[1])
  103.             p++;
  104.  
  105.         if(!*p) {
  106.             strcpy(file_match.filename,path);
  107.             restname=file_match.filename+(p-path);
  108.             strcpy(p,wildcard);
  109.             wilds=2;
  110.         }
  111.     }
  112.  
  113.         /* Then repeat until we run out of matches or user routine breaks */
  114. again:
  115.     for(code=SRCHFIR; DOS(code,0,ALLREALONES&type,path)!=-1; code=SRCHNXT)  {
  116.             /* Proceed to next one, if starts with dot and DOTHIDDEN */
  117.         if((type&(DOTHIDDEN|HIDDEN))==DOTHIDDEN &&
  118.             *file_match.shortname=='.' && *restname!='.') continue;
  119.             /* Copy shortname to full filename */
  120.         for(p=file_match.shortname, q=restname; *q++=*p=tolower(*p); p++);
  121.             /* Recurse if a directory name, but not "." or ".." */
  122.         if(type&RECURSIVE && file_match.attribute&DIRECTORY &&
  123.             (*file_match.shortname!='.' || !wilds)) {
  124. #ifdef    DEBUG
  125.                 printf(    "type&RECURSIVE=%02x, file_match.attribute&"
  126.                     "DIRECTORY=%02x, *file_match.shortname=%c, "
  127.                     "!wilds=%d\n",type&RECURSIVE,file_match.attribute&
  128.                     DIRECTORY,*file_match.shortname,!wilds);
  129. #endif
  130.                 /* Call user routine before anything else if DIRFIRST */
  131.             if(type&DIRFIRST)
  132.                 if(routine(&file_match)) return(-1);
  133.                 else count++;
  134.                 /* Then add wildcard to filename and call us again */
  135.             q[-1]=dirsepar;
  136.             strcpy(q,wildcard);
  137.             if((i=formatch(file_match.filename,type,routine))==-1) return(-1);
  138.                 /* Have to redo this because our other incarnation messed it */
  139.             BDOS(SETDMA, &file_match);
  140.             count+=i;
  141.             q[-1]='\0';
  142.             if(type&DIRFIRST) continue;
  143.         }
  144.  
  145.     /*    Call user routine only if not recursing and not at a '.';
  146.     **    then return minus one if user routine breaks, else zero
  147.     */
  148.     if(!(type&RECURSIVE) || !(file_match.attribute&DIRECTORY) ||
  149.         (*file_match.shortname!='.') || !wilds)
  150.         if(routine(&file_match)) return(-1);
  151.         else count++;
  152.     }
  153.  
  154.         /* If no wildcards, just test the filename */
  155.     if(!wilds && !count && type&MATCHNONWILD)   {
  156.         for(p=file_match.shortname, q=restname; *p++=*q++;);
  157.         file_match.attribute=0;
  158.         file_match.filetime=0L;
  159.         file_match.filesize=0L;
  160.         if(routine(&file_match)) return(-1);
  161.         else count++;
  162.     }
  163.  
  164.         /* Return number of times user routine called */
  165.     return(count);
  166. }
  167.  
  168.     /*
  169.     **  The first time 'round, get option and file separators
  170.     */
  171. void initmatch()    {
  172.     register char *p;
  173.  
  174.     if( (*optsepar = (p=getenv("SWITCHAR"))?*p:switchar(0)) == '/')
  175.         dirsepar='\\', othersepar='/';
  176.     else
  177.         dirsepar='/', othersepar='\\';
  178. }
  179.